﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RrslLite.Net.Contracts;
using RrslLite.Net.Messages;

namespace RrslLite.Net.Proxies
{
    public class AsyncDuplexMessageProcessorProxy : System.ServiceModel.DuplexClientBase<IAsyncWcfDuplexMessageService>, IAsyncWcfDuplexMessageService
    {
        private BeginOperationDelegate onBeginInvokeOperationsDelegate;

        private EndOperationDelegate onEndInvokeOperationsDelegate;

        private System.Threading.SendOrPostCallback onInvokeOperationsCompletedDelegate;

        private bool useGeneratedCallback;

        private BeginOperationDelegate onBeginOpenDelegate;

        private EndOperationDelegate onEndOpenDelegate;

        private System.Threading.SendOrPostCallback onOpenCompletedDelegate;

        private BeginOperationDelegate onBeginCloseDelegate;

        private EndOperationDelegate onEndCloseDelegate;

        private System.Threading.SendOrPostCallback onCloseCompletedDelegate;

        public AsyncDuplexMessageProcessorProxy(System.ServiceModel.InstanceContext callbackInstance) :
            base(callbackInstance)
        {
        }

        public AsyncDuplexMessageProcessorProxy(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName) :
            base(callbackInstance, endpointConfigurationName)
        {
        }

        public AsyncDuplexMessageProcessorProxy(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress) :
            base(callbackInstance, endpointConfigurationName, remoteAddress)
        {
        }

        public AsyncDuplexMessageProcessorProxy(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
            base(callbackInstance, endpointConfigurationName, remoteAddress)
        {
        }

        public AsyncDuplexMessageProcessorProxy(System.ServiceModel.InstanceContext callbackInstance, System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            base(callbackInstance, binding, remoteAddress)
        {
        }

        public AsyncDuplexMessageProcessorProxy(string endpointConfigurationName) :
            this(new WcfDuplexMessageServiceClientCallback(), endpointConfigurationName)
        {
        }

        private AsyncDuplexMessageProcessorProxy(WcfDuplexMessageServiceClientCallback callbackImpl, string endpointConfigurationName) :
            this(new System.ServiceModel.InstanceContext(callbackImpl), endpointConfigurationName)
        {
            useGeneratedCallback = true;
            callbackImpl.Initialize(this);
        }

        public AsyncDuplexMessageProcessorProxy(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            this(new WcfDuplexMessageServiceClientCallback(), binding, remoteAddress)
        {
        }

        private AsyncDuplexMessageProcessorProxy(WcfDuplexMessageServiceClientCallback callbackImpl, System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            this(new System.ServiceModel.InstanceContext(callbackImpl), binding, remoteAddress)
        {
            useGeneratedCallback = true;
            callbackImpl.Initialize(this);
        }

        public AsyncDuplexMessageProcessorProxy() :
            this(new WcfDuplexMessageServiceClientCallback())
        {
        }

        private AsyncDuplexMessageProcessorProxy(WcfDuplexMessageServiceClientCallback callbackImpl) :
            this(new System.ServiceModel.InstanceContext(callbackImpl))
        {
            useGeneratedCallback = true;
            callbackImpl.Initialize(this);
        }

        public event System.EventHandler<InvokeOperationsAsyncCompletedArgs> InvokeOperationsCompleted;

        public event System.EventHandler<InvokeOperationsAsyncCompletedArgs> ReceiveReceived;

        public event System.EventHandler<System.ComponentModel.AsyncCompletedEventArgs> OpenCompleted;

        public event System.EventHandler<System.ComponentModel.AsyncCompletedEventArgs> CloseCompleted;

        public event EventHandler Closed;
        public event EventHandler Closing;
        public event EventHandler Faulted;
        public event EventHandler Opened;
        public event EventHandler Opening;

        IAsyncResult IAsyncWcfDuplexMessageService.BeginInvokeOperations(Message[] messages, System.AsyncCallback callback, object asyncState)
        {
            return base.Channel.BeginInvokeOperations(messages, callback, asyncState);
        }

        void IAsyncWcfDuplexMessageService.EndInvokeOperations(IAsyncResult result)
        {
            base.Channel.EndInvokeOperations(result);
        }

        public void InvokeOperationsAsync(Message[] messages)
        {
            this.InvokeOperationsAsync(messages, null);
        }

        private System.IAsyncResult OnBeginInvokeOperations(object[] inValues, System.AsyncCallback callback, object asyncState)
        {
            this.VerifyCallbackEvents();
            Message[] messages = ((Message[])(inValues[0]));
            return ((IAsyncWcfDuplexMessageService)(this)).BeginInvokeOperations(messages, callback, asyncState);
        }

        private object[] OnEndInvokeOperations(System.IAsyncResult result)
        {
            ((IAsyncWcfDuplexMessageService)(this)).EndInvokeOperations(result);
            return null;
        }

        private void OnInvokeOperationsCompleted(object state)
        {
            if ((this.InvokeOperationsCompleted != null))
            {
                InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
                this.InvokeOperationsCompleted(this, new InvokeOperationsAsyncCompletedArgs(e.Results, e.Error, e.Cancelled, e.UserState));
            }
        }

        public void InvokeOperationsAsync(Message[] messages, object userState)
        {
            if ((this.onBeginInvokeOperationsDelegate == null))
            {
                this.onBeginInvokeOperationsDelegate = new BeginOperationDelegate(this.OnBeginInvokeOperations);
            }
            if ((this.onEndInvokeOperationsDelegate == null))
            {
                this.onEndInvokeOperationsDelegate = new EndOperationDelegate(this.OnEndInvokeOperations);
            }
            if ((this.onInvokeOperationsCompletedDelegate == null))
            {
                this.onInvokeOperationsCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnInvokeOperationsCompleted);
            }
            base.InvokeAsync(this.onBeginInvokeOperationsDelegate, new object[] {
                        messages}, this.onEndInvokeOperationsDelegate, this.onInvokeOperationsCompletedDelegate, userState);
        }

        private void OnReceiveReceived(object state)
        {
            if ((this.ReceiveReceived != null))
            {
                object[] results = ((object[])(state));
                this.ReceiveReceived(this, new InvokeOperationsAsyncCompletedArgs(results, null, false, null));
            }
        }

        private void VerifyCallbackEvents()
        {
            if (((this.useGeneratedCallback != true)
                        && (this.ReceiveReceived != null)))
            {
                throw new System.InvalidOperationException("Callback events cannot be used when the callback InstanceContext is specified. Pl" +
                        "ease choose between specifying the callback InstanceContext or subscribing to th" +
                        "e callback events.");
            }
        }

        private System.IAsyncResult OnBeginOpen(object[] inValues, System.AsyncCallback callback, object asyncState)
        {
            this.VerifyCallbackEvents();
            return ((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(callback, asyncState);
        }

        private object[] OnEndOpen(System.IAsyncResult result)
        {
            ((System.ServiceModel.ICommunicationObject)(this)).EndOpen(result);
            return null;
        }

        private void OnOpenCompleted(object state)
        {
            if ((this.OpenCompleted != null))
            {
                InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
                this.OpenCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
            }
        }

        public void OpenAsync()
        {
            this.OpenAsync(null);
        }

        public void OpenAsync(object userState)
        {
            if ((this.onBeginOpenDelegate == null))
            {
                this.onBeginOpenDelegate = new BeginOperationDelegate(this.OnBeginOpen);
            }
            if ((this.onEndOpenDelegate == null))
            {
                this.onEndOpenDelegate = new EndOperationDelegate(this.OnEndOpen);
            }
            if ((this.onOpenCompletedDelegate == null))
            {
                this.onOpenCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnOpenCompleted);
            }
            base.InvokeAsync(this.onBeginOpenDelegate, null, this.onEndOpenDelegate, this.onOpenCompletedDelegate, userState);
        }

        private System.IAsyncResult OnBeginClose(object[] inValues, System.AsyncCallback callback, object asyncState)
        {
            return ((System.ServiceModel.ICommunicationObject)(this)).BeginClose(callback, asyncState);
        }

        private object[] OnEndClose(System.IAsyncResult result)
        {
            ((System.ServiceModel.ICommunicationObject)(this)).EndClose(result);
            return null;
        }

        private void OnCloseCompleted(object state)
        {
            if ((this.CloseCompleted != null))
            {
                InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
                this.CloseCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
            }
        }

        public void CloseAsync()
        {
            this.CloseAsync(null);
        }

        public void CloseAsync(object userState)
        {
            if ((this.onBeginCloseDelegate == null))
            {
                this.onBeginCloseDelegate = new BeginOperationDelegate(this.OnBeginClose);
            }
            if ((this.onEndCloseDelegate == null))
            {
                this.onEndCloseDelegate = new EndOperationDelegate(this.OnEndClose);
            }
            if ((this.onCloseCompletedDelegate == null))
            {
                this.onCloseCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnCloseCompleted);
            }
            base.InvokeAsync(this.onBeginCloseDelegate, null, this.onEndCloseDelegate, this.onCloseCompletedDelegate, userState);
        }

        //protected override IAsyncWcfDuplexMessageService CreateChannel()
        //{
        //    return new WcfDuplexMessageServiceClientChannel(this);
        //}

        private class WcfDuplexMessageServiceClientCallback : object, IAsyncWcfDuplexMessageServiceCallback
        {

            private AsyncDuplexMessageProcessorProxy proxy;

            public void Initialize(AsyncDuplexMessageProcessorProxy proxy)
            {
                this.proxy = proxy;
            }

            public void Receive(Message[] messages)
            {
                this.proxy.OnReceiveReceived(new object[] {
                            messages});
            }
        }

        //private class WcfDuplexMessageServiceClientChannel : ChannelBase<IAsyncWcfDuplexMessageService>, IAsyncWcfDuplexMessageService
        //{

        //    public WcfDuplexMessageServiceClientChannel(System.ServiceModel.DuplexClientBase<IAsyncWcfDuplexMessageService> client) :
        //        base(client)
        //    {
        //    }

        //    public System.IAsyncResult BeginInvokeOperations(Message[] messages, System.AsyncCallback callback, object asyncState)
        //    {
        //        object[] _args = new object[1];
        //        _args[0] = messages;
        //        System.IAsyncResult _result = base.BeginInvoke("InvokeOperations", _args, callback, asyncState);
        //        return _result;
        //    }

        //    public void EndInvokeOperations(System.IAsyncResult result)
        //    {
        //        object[] _args = new object[0];
        //        base.EndInvoke("InvokeOperations", _args, result);
        //    }

        //    public event EventHandler<InvokeOperationsAsyncCompletedArgs> ReceiveReceived;
        //}
    }
}
